package com.zmn.oms.zmn.business.impl.chan;

import com.alibaba.fastjson.JSON;
import com.zmn.common.constant.GlobalConsts;
import com.zmn.common.constant.StatusConsts;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.oms.common.constant.OrderClueConsts;
import com.zmn.oms.common.constant.RedisKeyConsts;
import com.zmn.oms.common.exception.OmsBaseException;
import com.zmn.oms.common.exception.chan.ChannelFacadeException;
import com.zmn.oms.manager.utils.LockUtil;
import com.zmn.oms.model.dto.chan.OrderClueDetailDTO;
import com.zmn.oms.model.dto.chan.OrderClueDetailListQuery;
import com.zmn.oms.model.entity.chan.FacadeMessage;
import com.zmn.oms.model.entity.chan.FacadeMessageEvent;
import com.zmn.oms.model.entity.chan.OrderClue;
import com.zmn.oms.model.entity.chan.OrderClueDetail;
import com.zmn.oms.services.interfaces.chan.FacadeSyncService;
import com.zmn.oms.services.interfaces.chan.OrderClueDetailService;
import com.zmn.oms.services.interfaces.orderpay.AccountPayBService;
import com.zmn.oms.zmn.business.interfaces.chan.FacadeMessageBService;
import com.zmn.oms.zmn.business.interfaces.chan.FacadeOrderClueBService;
import com.zmn.oms.zmn.business.interfaces.chan.FacadeOrderClueDetailBService;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * 类描述：
 *
 * @author lhl
 * @date 2020/12/29 16:28
 */
@Slf4j
@Service("facadeOrderClueDetailBService")
public class FacadeOrderClueDetailBServiceImpl implements FacadeOrderClueDetailBService {

    @Autowired
    private OrderClueDetailService orderClueDetailService;
    @Autowired
    private FacadeOrderClueBService facadeOrderClueBService;
    @Autowired
    private FacadeSyncService facadeSyncService;
    @Autowired
    private FacadeMessageBService facadeMessageBServices;
    @Autowired
    private AccountPayBService accountPayBService;

//    @Reference(version = com.zmn.base.plat.engine.common.constant.DubboConsts.INTERFACE_VERSION , check = false)
//    private FactoryListRemoteService factoryListRemoteService;
    /**
     *  保存渠道订单线索详情（线索单）
     * @param orderClueDetail 渠道订单线索详情对象，该对象的 clueId 字段不能为null
     * @throws ChannelFacadeException 当保存失败时被抛出
     */
    @Transactional
    @Override
    public void saveOrderClueDetail(OrderClueDetail orderClueDetail) throws ChannelFacadeException {
        OrderClue dbOrderClue = facadeOrderClueBService.findOrderClueByKey(orderClueDetail.getClueId());
        if (dbOrderClue == null) {
            throw new ChannelFacadeException("未找到对应的订单线索");
        }

        OrderClueDetail dbOrderClueDetail = orderClueDetailService.findByKey(orderClueDetail.getClueId());
        if (dbOrderClueDetail != null) {
            if (Objects.equals(OrderClueConsts.DETAIL_STATE_ORDER_APPLIED, dbOrderClueDetail.getState())) {
                try {
                    OrderClueDetail updateModel = new OrderClueDetail();
                    updateModel.setClueId(orderClueDetail.getClueId());
                    updateModel.setState(OrderClueConsts.DETAIL_STATE_PENDING);
                    orderClueDetailService.updateByKey(updateModel);
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }
            }
            return; // 线索已存在
        }

        orderClueDetail.setFacadeId(dbOrderClue.getFacadeId());
        orderClueDetail.setOuterId(dbOrderClue.getOuterId());
        Optional.ofNullable(dbOrderClue.getChannelId())
                .ifPresent(channelId -> orderClueDetail.setChannelId(channelId));
        try {
            orderClueDetailService.save(orderClueDetail);

            // 记录此订单线索录单失败
            facadeOrderClueBService.updateStateByKey(dbOrderClue.getId(), OrderClueConsts.CLUE_STATE_DETAIL_PENDING);
        } catch (Exception e) {
            throw new ChannelFacadeException(e.getMessage(), e);
        }
    }

    /**
     * 条件查询
     * @param clueId
     * @return
     */
    @Override
    public OrderClueDetail findOrderClueDetailByClueId(Long clueId) {
        return orderClueDetailService.findByKey(clueId);
    }

    /**
     * 查询线索单
     * @param query
     * @return
     */
    @Override
    public List<OrderClueDetail> listOrderClueDetails(OrderClueDetailListQuery query) {
        // TODO -lhl 待实现

        List<OrderClueDetail> list = orderClueDetailService.listOrderClueDetails(query);
        return list;
    }

    /**
     * 舍弃该订单线索（将状态置为忽略状态）
     * @param detailDTO
     * @throws ChannelFacadeException 当该线索的状态不允许变更为忽略状态时（已执行生成订单操作）被抛出
     */
    @Transactional
    @Override
    public OrderClueDetail ignoreOrderClueDetail(OrderClueDetailDTO detailDTO) throws ChannelFacadeException {
        if (detailDTO == null || detailDTO.getClueId() == null || detailDTO.getOperatorId() == null) {
            log.info("facadeOrderClueDetailBService.ignoreOrderClueDetail: OrderClueDetailDTO=[{}]",
                    JSON.toJSONString(detailDTO));
            throw new ChannelFacadeException("参数不全");
        }

        Long clueId = detailDTO.getClueId();

        OrderClueDetail dbOrderClueDetail = orderClueDetailService.findByKey(clueId);
        if (dbOrderClueDetail == null) {
            throw new ChannelFacadeException("线索单不存在");
        }
        switch (dbOrderClueDetail.getState()) {
            case OrderClueConsts.DETAIL_STATE_IGNORED:
                return dbOrderClueDetail;
            case OrderClueConsts.DETAIL_STATE_ORDER_APPLIED:
                throw new ChannelFacadeException("该线索单已申请生成订单");
            case OrderClueConsts.DETAIL_STATE_ORDERED:
                throw new ChannelFacadeException("该线索单已生成订单");
        }

        OrderClueDetail updateModel = new OrderClueDetail();
        updateModel.setClueId(clueId);
        updateModel.setState(OrderClueConsts.DETAIL_STATE_IGNORED);
        updateModel.setOperator(detailDTO.getOperator());
        updateModel.setOperatorId(detailDTO.getOperatorId());
        orderClueDetailService.updateByKey(updateModel);

        facadeOrderClueBService.updateStateByKey(clueId, OrderClueConsts.CLUE_STATE_DETAIL_DONE);

        dbOrderClueDetail.setState(updateModel.getState());
        dbOrderClueDetail.setOperatorId(updateModel.getOperatorId());
        dbOrderClueDetail.setOperator(updateModel.getOperator());
        return dbOrderClueDetail;
    }

    /**
     * 申请生成系统订单
     * @param detailDTO
     * @throws ChannelFacadeException 以下情形时被抛出：
     *      1. 该线索单的状态不是0（待处理）；
     *      2. 该线索已生成订单：错误码 201（StatusConsts.STATUS_SUCCESS_NEXT）；
     *      3. 该线索已申请生成订单且申请未被处理：错误码 201（StatusConsts.STATUS_SUCCESS_NEXT）；
     */
    @Transactional
    @Override
    public OrderClueDetail apply2ZmnOrder(OrderClueDetailDTO detailDTO) throws ChannelFacadeException {
        if (detailDTO == null || detailDTO.getClueId() == null || detailDTO.getOperatorId() == null) {
            log.info("facadeOrderClueDetailBService.apply2ZmnOrder: OrderClueDetailDTO=[{}]",
                    JSON.toJSONString(detailDTO));
            throw new ChannelFacadeException(StatusConsts.ERROR_PARAMS, "参数不全");
        }

        Long clueId = detailDTO.getClueId();
        OrderClueDetail dbOrderClueDetail = orderClueDetailService.findByKey(clueId);
        if (dbOrderClueDetail == null) {
            throw new ChannelFacadeException(StatusConsts.ERROR_EMPTY, "线索单不存在");
        }
        switch (dbOrderClueDetail.getState()) {
            case OrderClueConsts.DETAIL_STATE_IGNORED:
                return dbOrderClueDetail;
            case OrderClueConsts.DETAIL_STATE_ORDERED:
                throw new ChannelFacadeException(StatusConsts.STATUS_SUCCESS_NEXT, "该线索单已生成订单");
        }

        // 厂商单，校验厂商余额
        if (Objects.equals(com.zmn.consts.GlobalConsts.BIZ_TYPE_F, dbOrderClueDetail.getBizType())) {
            Integer channelId = dbOrderClueDetail.getChannelId();
            do {
                if (channelId == null || channelId.intValue() == 0) {
                    continue;
                }

                try {
                    throw new ChannelFacadeException("厂商服务已下线");
                    /*ResponseDTO<FactoryBaseDRO> factoryBaseResp = factoryListRemoteService.getFactoryByChannelId(channelId);
                    FactoryBaseDRO factoryBaseDRO = factoryBaseResp.getData();
                    if (factoryBaseDRO == null || factoryBaseDRO.getFcId() == null) {
                        throw new ChannelFacadeException(StatusConsts.STATU_SERROR_SYSTEM, "未找到对应的厂商");
                    }

                    ResponseDTO<FactoryDRO> factoryResp = factoryListRemoteService.getFactoryById(factoryBaseDRO.getFcId());
                    FactoryDRO factoryDRO = factoryResp.getData();
                    if (factoryDRO == null || factoryDRO.getUserId() == null) {
                        throw new ChannelFacadeException(StatusConsts.STATU_SERROR_SYSTEM, "厂商信息有误");
                    }

                    int forzenAmount = Optional.ofNullable(factoryDRO.getForzenAmount()).orElse(15000);
                    int productNumber = Optional.ofNullable(dbOrderClueDetail.getProductNumber())
                            .filter(num -> num > 0)
                            .orElse(1);
                    int shouldFreezeAmount = (forzenAmount * productNumber);
                    try {
                        accountPayBService.checkAccount(factoryBaseDRO.getFcId(), shouldFreezeAmount);
                    } catch (OmsBaseException e) {
                        throw new ChannelFacadeException(StatusConsts.STATU_SERROR_SYSTEM, e.getMessage());
                    }*/
                } catch (Exception e) {
                    if (e instanceof ChannelFacadeException) {
                        throw e;
                    }
                    log.error(e.getMessage(), e);
                    throw new ChannelFacadeException(StatusConsts.STATU_SERROR_SYSTEM, "系统异常", e);
                }
            } while (false);
        }

        LockUtil.Lock lock = null;
        try {
            String key = String.format(RedisKeyConsts.CHANNEL_FACADE_LOCK_KEY, "apply2ZmnOrder", String.valueOf(clueId));
            lock = LockUtil.getLock(key);
            if (lock == null) {
                throw new ChannelFacadeException(StatusConsts.STATUS_SUCCESS_NEXT, "该线索单已被他人提交申请");
            }
        } catch (Exception e) {
            if (e instanceof ChannelFacadeException) {
                throw (ChannelFacadeException) e;
            }
            throw new ChannelFacadeException(StatusConsts.STATU_SERROR_SYSTEM, "系统异常", e);
        }

        try {
            OrderClueDetail updateModel = new OrderClueDetail();
            updateModel.setClueId(clueId);
            updateModel.setState(OrderClueConsts.DETAIL_STATE_ORDER_APPLIED);
            updateModel.setOperator(detailDTO.getOperator());
            updateModel.setOperatorId(detailDTO.getOperatorId());
            orderClueDetailService.updateByKey(updateModel);

            // 通知系统创建新单
            FacadeMessageEvent event = new FacadeMessageEvent();
            event.setRetriable(GlobalConsts.NO);
            event.setFacadeId(dbOrderClueDetail.getFacadeId());
            event.setClueId(dbOrderClueDetail.getClueId());
            event.setChannelId(dbOrderClueDetail.getChannelId());
            event.setOpTime(new Date());

            FacadeMessage dbFacadeMessage = facadeMessageBServices.findByClueIdAndMsgNo(clueId, 1);
            event.setContent(dbFacadeMessage.getContent());
            event.setTag(dbFacadeMessage.getEventTag());
            event.setFun(dbFacadeMessage.getEventFun());
            event.setMessageNo(dbFacadeMessage.getMessageNo());

            facadeSyncService.sendFacadeMessageEventSync(event);

            dbOrderClueDetail.setState(updateModel.getState());
            dbOrderClueDetail.setOperatorId(updateModel.getOperatorId());
            dbOrderClueDetail.setOperator(updateModel.getOperator());
            return dbOrderClueDetail;
        } catch (Exception e) {
            lock.close();
            log.error(e.getMessage(), e);
            throw new ChannelFacadeException(StatusConsts.STATU_SERROR_SYSTEM, String.format("系统异常：%s", e.getMessage()), e);
        }
    }

    /**
     * 将该线索单重置为“待处理”状态
     * @param detailDTO
     * @throws ChannelFacadeException 当该线索的状态不是“已忽略”时被抛出
     */
    @Transactional
    @Override
    public OrderClueDetail resetState2Pending(OrderClueDetailDTO detailDTO) throws ChannelFacadeException {
        if (detailDTO == null || detailDTO.getClueId() == null || detailDTO.getOperatorId() == null) {
            log.info("facadeOrderClueDetailBService.resetState2Pending: OrderClueDetailDTO=[{}]",
                    JSON.toJSONString(detailDTO));
            throw new ChannelFacadeException("参数不全");
        }

        Long clueId = detailDTO.getClueId();
        OrderClueDetail dbOrderClueDetail = orderClueDetailService.findByKey(clueId);
        if (dbOrderClueDetail == null) {
            throw new ChannelFacadeException("线索单不存在");
        }
        switch (dbOrderClueDetail.getState()) {
            case OrderClueConsts.DETAIL_STATE_PENDING:
            case OrderClueConsts.DETAIL_STATE_ORDER_APPLIED:
                return dbOrderClueDetail;
            case OrderClueConsts.DETAIL_STATE_ORDERED:
                throw new ChannelFacadeException("该线索单已生成订单");
        }

        OrderClueDetail updateModel = new OrderClueDetail();
        updateModel.setClueId(clueId);
        updateModel.setState(OrderClueConsts.DETAIL_STATE_PENDING);
        updateModel.setOperator(detailDTO.getOperator());
        updateModel.setOperatorId(detailDTO.getOperatorId());
        orderClueDetailService.updateByKey(updateModel);

        facadeOrderClueBService.updateStateByKey(clueId, OrderClueConsts.CLUE_STATE_DETAIL_PENDING);

        dbOrderClueDetail.setState(updateModel.getState());
        dbOrderClueDetail.setOperatorId(updateModel.getOperatorId());
        dbOrderClueDetail.setOperator(updateModel.getOperator());
        return dbOrderClueDetail;
    }

    /**
     * 将该线索单标记为“已生成订单”状态，并保存系统单号
     * @param clueId
     * @param zmnOrderId
     * @throws ChannelFacadeException 当参数不全时被抛出
     */
    @Transactional
    @Override
    public OrderClueDetail saveZmnOrderIdByKey(Long clueId, Long zmnOrderId) throws ChannelFacadeException {
        if (clueId == null || zmnOrderId == null) {
            log.info("facadeOrderClueDetailBService.mark2ZmnOrder: clueId=[{}], zmnOrderId=[{}]",
                    String.valueOf(clueId), String.valueOf(zmnOrderId));
            throw new ChannelFacadeException("参数不全");
        }

        OrderClueDetail dbOrderClueDetail = orderClueDetailService.findByKey(clueId);
        boolean hasClueDetail = (dbOrderClueDetail != null);

        facadeOrderClueBService.saveZmnOrderIdByKey(clueId, zmnOrderId,
                hasClueDetail ? OrderClueConsts.CLUE_STATE_DETAIL_DONE : OrderClueConsts.CLUE_STATE_NON_DETAIL);

        if (hasClueDetail && !Objects.equals(OrderClueConsts.DETAIL_STATE_ORDERED, dbOrderClueDetail.getState())) {
            OrderClueDetail updateModel = new OrderClueDetail();
            updateModel.setClueId(clueId);
            updateModel.setState(OrderClueConsts.DETAIL_STATE_ORDERED);
            updateModel.setZmnOrderId(zmnOrderId);
            orderClueDetailService.updateByKey(updateModel);

            dbOrderClueDetail.setState(updateModel.getState());
            dbOrderClueDetail.setZmnOrderId(updateModel.getZmnOrderId());
        }

        return dbOrderClueDetail;
    }
}
